// 全局变量
/*
全局变量的生命周期肯定是'static，但是不代表它需要用static来声明
    例如常量、字符串字面值等无需使用static进行声明，原因是它们已经被打包到二进制可执行文件中。
*/

/*

静态常量
    全局常量可以在程序任何一部分使用，当然，如果它是定义在某个模块中，你需要引入对应的模块才能使用。
        常量，顾名思义它是不可变的，很适合用作静态配置

常量与普通变量的区别
    关键字是const而不是let
    定义常量必须指明类型（如 i32）不能省略
    定义常量时变量的命名规则一般是全部大写
    常量可以在任意作用域进行定义，其生命周期贯穿整个程序的生命周期。
        编译时编译器会尽可能将其内联到代码中，所以在不同地方对同一常量的引用并不能保证引用到相同的内存地址
    常量的赋值只能是常量表达式/数学表达式，也就是说必须是在编译期就能计算出的值，
        如果需要在运行时才能得出结果的值比如函数，则不能赋值给常量表达式
    对于变量出现重复的定义(绑定)会发生变量遮盖，后面定义的变量会遮住前面定义的变量，常量则不允许出现重复的定义

静态变量和常量的区别
    静态变量不会被内联，在整个程序中，静态变量只有一个实例，所有的引用都会指向同一个地址
    存储在静态变量中的值必须要实现 Sync trait

*/

// 静态初始化有一个致命的问题：无法用函数进行静态初始化
#[cfg(test)]
mod staticx {
    use std::sync::atomic::{AtomicUsize, Ordering};

    const CONST_DATA: usize = usize::MAX / 2;
    static mut STATIC_MUT: usize = usize::MAX / 2;

    // 静态常量
    #[test]
    fn main() {
        let mut request_recv: usize = 0; // 静态变量   函数局部 

        println!("用户ID允许的最大值是{}", CONST_DATA);
        // Rust 要求必须使用unsafe语句块才能访问和修改static变量  当在多线程中同时去修改时，会不可避免的遇到脏数据
        request_recv += 1; // 函数局部 不需要
        assert_eq!(request_recv, 1);

        // CONST_DATA += 1; // 不可以修改

        unsafe {
            STATIC_MUT += 1; //全局静态变量在多线程环境下会存在 数据竞争 的风险
        }
    }

    static REQUEST_RECV_ATOMIC: AtomicUsize = AtomicUsize::new(0);

    #[test]
    fn atomic() {
        for _ in 0..100 {
            REQUEST_RECV_ATOMIC.fetch_add(1, Ordering::Relaxed);
        }
        println!("当前用户请求数{:?}", REQUEST_RECV_ATOMIC);
    }
}

// 静态初始化有一个致命的问题：无法用函数进行静态初始化
#[cfg(test)]
mod lazy_static {
    use std::collections::HashMap;

    use lazy_static::lazy_static;

    // 使用lazy_static在每次访问静态变量时，会有轻微的性能损失，因为其内部实现用了一个底层的并发原语std::sync::Once，
    //      在每次访问该变量时，程序都会执行一次原子指令用于确认静态变量的初始化是否完成。
    // lazy_static宏，匹配的是static ref，所以定义的静态变量都是不可变引用
    lazy_static! {
        static ref HASHMAP: HashMap<u32, &'static str> = {
            let mut m = HashMap::new();
            m.insert(0, "foo");
            m.insert(1, "bar");
            m.insert(2, "baz");
            m
        };
    }
    // lazy_static直到运行到main中的第一行代码时，才进行初始化，非常lazy static

    #[test]
    fn main() {
        // 首次访问`HASHMAP`的同时对其进行初始化
        println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());

        // 后续的访问仅仅获取值，再不会进行任何初始化操作
        println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap());
    }
}

// 静态初始化有一个致命的问题：无法用函数进行静态初始化
#[cfg(test)]
mod box_leek {
    #[derive(Debug)]
    struct Config {
        a: String,
        b: String,
    }

    #[test]
    fn change_static() {
        static mut CONFIG: Option<&mut Config> = None;

        let c = Box::new(Config {
            a: "A".to_string(),
            b: "B".to_string(),
        });
        unsafe {
            // 将`c`从内存中泄漏，变成`'static`生命周期
            CONFIG = Some(Box::leak(c));
            // println!("{:?}", CONFIG);
        }
        unsafe {
            // Rust 的借用和生命周期规则限制了我们做到这一点
            // 因为试图将一个局部生命周期的变量赋值给全局生命周期的CONFIG，这明显是不安全的

            // CONFIG = Some(&mut Config {
            //     a: "A".to_string(),
            //     b: "B".to_string(),
            // });
            // println!("{:?}", CONFIG);
        }
    }

    fn init() -> Option<&'static mut Config> {
        // Some(&mut Config {
        //     a: "A".to_string(),
        //     b: "B".to_string(),
        // });
        let c = Box::new(Config {
            a: "A".to_string(),
            b: "B".to_string(),
        });
        // Box::leak 解决生命周期
        Some(Box::leak(c))
    }

    #[test]
    fn main() {
        static mut CONFIG: Option<&mut Config> = None;
        unsafe {
            CONFIG = init();
            // println!("{:?}", CONFIG)
        }
    }
}

// cell::OnceCell 和 sync::OnceLock )两种 Cell
// 前者用于单线程，后者用于多线程，它们用来存储堆上的信息，并且具有最 多只能赋值一次的特性

#[cfg(test)]
mod once_cell {
    // 低于Rust 1.70版本
    // static LOGGER: SyncOnceCell<Logger> = SyncOnceCell::new();

    use std::sync::OnceLock;
    use std::thread;

    // Rust 1.70版本以上
    static LOGGER: OnceLock<Logger> = OnceLock::new();

    #[derive(Debug)]
    struct Logger;
    impl Logger {
        fn global() -> &'static Logger {
            // 一个 global() 关联函数，并在其内部调用 get_or_init 进行初始化 Logger
            // 之后在不同线程上多次调用 Logger::global() 获取其实例

            // 获取或初始化 Logger
            LOGGER.get_or_init(|| {
                println!("Logger is being created..."); // 初始化打印
                Logger
            })
        }

        fn log(&self, message: String) {
            println!("{}", message)
        }
    }

    #[test]
    fn main() {
        // 子线程中调用
        let handle = thread::spawn(|| {
            let logger = Logger::global();
            logger.log("thread message".to_string());
        });

        // 主线程调用
        let logger = Logger::global();
        logger.log("some message".to_string());

        let logger2 = Logger::global();
        logger2.log("other message".to_string());

        handle.join().unwrap();
    }
}
